﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Workflow;
using System.Runtime.Serialization;
using System.IO;
using System.Xml;

/**
 * Copyright 2011 by Alberto Gemin
 * agemin@hotmail.com
 * Version 1.7.0.1
 * 13 Dec 2011
 **/
namespace Gemina.CRM2011.WF.LdgManager
{

    /// <summary>
    /// Custom base class for all Code Activities.
    /// </summary>
    public abstract class AgCodeActivityBase : CodeActivity
    {

        #region Constants
        
        private const string MsgInvalidViewDefinition = "Error deserializing entity(ies) from View Definition(s). The object is of type {0} instead than of expected type {1}";

        #endregion

        #region Properties

        /// <summary>
        /// Primary Key of the entity the WF runs on.
        /// </summary>
        public Guid CurrentRecordId { get; set; }

        /// <summary>
        /// Name of the entity the WF runs on.
        /// </summary>
        public string CurrentEntityName { get; set; }

        /// <summary>
        /// Operation that triggered the workflow.
        /// </summary>
        public string CurrentOperation { get; set; }

        #endregion

        #region CodeActivity

        /// <summary>
        /// Workflow step.
        /// </summary>
        protected override void Execute(CodeActivityContext executionContext)
        {
            try
            {
                IWorkflowContext workflowContext = executionContext.GetExtension<IWorkflowContext>();
                this.CurrentRecordId = workflowContext.PrimaryEntityId;
                this.CurrentOperation = workflowContext.MessageName;
                this.CurrentEntityName = workflowContext.PrimaryEntityName;

                this.ExecuteBody(executionContext);
            }
            catch (AgErrorMessage ex)
            {
                throw new InvalidPluginExecutionException(OperationStatus.Failed, ex.Message);
            }
            catch (Exception ex)
            {
                throw new InvalidPluginExecutionException(OperationStatus.Failed, ex.ToString());
            }
        }

        /// <summary>
        /// Overridden in derived classes: contains the actual workflow step.
        /// </summary>
        protected abstract bool ExecuteBody(CodeActivityContext executionContext);

        #endregion

        #region Protected Methods

        protected IOrganizationService GetService(CodeActivityContext executionContext, Guid? user)
        {
            IOrganizationServiceFactory svcFactory = executionContext.GetExtension<IOrganizationServiceFactory>();

            if (user == null)
            {
                IWorkflowContext workflowContext = executionContext.GetExtension<IWorkflowContext>();
                return svcFactory.CreateOrganizationService(workflowContext.UserId);
            }
            else
            {
                return svcFactory.CreateOrganizationService(user);
            }
        }

        protected IOrganizationService GetService(CodeActivityContext executionContext)
        {
            return this.GetService(executionContext, null);
        }

        protected string Serialize(Object obj)
        {
            DataContractSerializer serializer = new DataContractSerializer(obj.GetType());
            StringWriter result = new StringWriter();

            using (XmlTextWriter writer = new XmlTextWriter(result))
            {
                serializer.WriteObject(writer, obj);
            }

            return result.GetStringBuilder().ToString();
        }

        protected Entity DeserializeEntity(string str)
        {
            DataContractSerializer serializer = new DataContractSerializer(typeof(Entity));
            StringReader sr = new StringReader(str);

            using (XmlTextReader reader = new XmlTextReader(sr))
            {
                Object obj = serializer.ReadObject(reader);
                if (!(obj is Entity))
                {
                    throw new AgErrorMessage(String.Format(MsgInvalidViewDefinition, obj.GetType().ToString(), typeof(Entity).ToString()));
                }
                Entity ent = (Entity)obj;
                return ent;
            }
        }

        protected List<Entity> DeserializeEntities(string str)
        {
            DataContractSerializer serializer = new DataContractSerializer(typeof(List<Entity>));
            StringReader sr = new StringReader(str);

            using (XmlTextReader reader = new XmlTextReader(sr))
            {
                Object obj = serializer.ReadObject(reader);
                if (!(obj is List<Entity>))
                {
                    throw new AgErrorMessage(String.Format(MsgInvalidViewDefinition, obj.GetType().ToString(), typeof(List<Entity>).ToString()));
                }
                List<Entity> ent = (List<Entity>)obj;
                return ent;
            }
        }

        #endregion

    }

}
